/* tcpcntl.c - tcpcntl */

#include "tcpfms.h"
#include "tcb.h"
#include "port.h"
#include "tcpstat.h"

int tcpuopt(struct tcb *, int, u_int);
extern int tcpstat(struct tcb *ptcb, struct tcpstat *tcps);


/*------------------------------------------------------------------------
 *  tcpcntl - control function for TCP pseudo-devices
 *------------------------------------------------------------------------
 */
int tcpcntl(int slot, int func, void *arg, void *arg2)
{
    if(slot <= 0 || slot > NTCP)
        return SYSERR;
    struct	tcb	*ptcb = tcbtab[slot];
    int		rv;

    if (ptcb == NULL || ptcb->tcb_state == TCPS_FREE)
        return SYSERR;

    sem_wait(&(ptcb->tcb_mutex));
    if (ptcb->tcb_state == TCPS_FREE) /* verify no state change */
            return SYSERR;

    switch (func) {
        case TCPC_ACCEPT:
            if (ptcb->tcb_type != TCPT_SERVER) {
                    rv = SYSERR;
                    break;
            }
            sem_post(&(ptcb->tcb_mutex));
            return port_recvmsg(ptcb->tcb_listenq);
        case TCPC_LISTENQ:
            rv = tcplq(ptcb, (int)arg);
            break;
        case TCPC_STATUS:	rv = tcpstat(ptcb, (struct tcpstat *)arg);
                                break;
        case TCPC_SOPT:
        case TCPC_COPT:		rv = tcpuopt(ptcb, func, (u_int)arg);
                                break;
        case TCPC_SENDURG:	//
                                // tcpwr acquires and releases tcb_mutex
                                // itself.
                                //
                                sem_post(&(ptcb->tcb_mutex));
                                return tcpwr(slot, (u_char *)arg,
                                        (unsigned)arg2, TWF_URGENT);
        default:
                rv = SYSERR;
    }
    sem_post(&(ptcb->tcb_mutex));
    return rv;
}
